/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package grex.fitnessfunctions;

import grex.GP;
import grex.Population;
import java.util.HashSet;
import java.util.Set;

/**
 *
 * @author RIK
 */
public class ParsimonyPressure {
    
   // double oldPressure =0.01;
    boolean activated =false;
     public double calcParsimonyPressure(GP[] population, double targetLength){ 
        /*int size = population.length;
     //  double currentPressure = population[0].getOptions().getPUNISHMENT_FOR_LENGTH();
        double length = population[0].getLength();
        double fitness = population[0].getFitness();// - currentPressure * population[0].getLength();
        
        double sum_sq_length = 0;
        double sum_sq_fitness = 0;
        double sum_coproduct = 0;
        
        double mean_length = length;
        double mean_fitness = fitness; 
        for(int p=1;p<size;p++){ 
            int i=1;
            length = population[p].getLength();
            fitness = population[p].getFitness();// - currentPressure * population[p].getLength();
            i++;
            double sweep =Double.valueOf(i-1)/i;
            double delta_length = length-mean_length;
            double delta_fitness = fitness-mean_fitness;
            sum_sq_length += delta_length * delta_length * sweep;
            sum_sq_fitness += delta_fitness * delta_fitness * sweep;
            sum_coproduct += delta_length * delta_fitness * sweep;
            mean_length += delta_length / i;
            mean_fitness += delta_fitness / i;
        }
       // double pop_sd_length = (double) Math.sqrt(sum_sq_length/size);
       // double pop_sd_fitness = (double) Math.sqrt(sum_sq_fitness/size);
        
        double cov_length_fitness = sum_coproduct / size;
        
        double lengthVariance = sum_sq_length/size;
        double fitnessVariance = sum_sq_fitness/size;*/
        
        double var = calcSizeVariance(population);
        double cVar = calcCoVariance(population);
        
        double pressure = cVar/var;  
        
         
        
       /* double pressure = -(cov_length_fitness - (targetLength-mean_length)*mean_fitness)/
                          (lengthVariance - (targetLength-mean_length)*mean_length);
        
        if(!activated && mean_length<targetLength)
            pressure = 0;            
        else
            activated =true;//*/
       // System.out.println("COV: " + cov_length_fitness+ " lenVAR: " + lengthVariance + " FitVAR: " + fitnessVariance + " MeanLen: " + mean_length + " MeanFitness: " + mean_fitness +" Pressure: " + pressure);
        return pressure;
    }
     
     private double calcSingleSizeVariance(GP[] pop){
         Set<Double> s = new HashSet<Double>();
         double sum=0;
         for(int i = 0; i < pop.length;i++){
             if(s.add(pop[i].getNrOfNodes())){
                 sum+=pop[i].getNrOfNodes();
             }
         }
         double mean = sum / s.size();
         sum=0;
         for(Double d:s){
             sum+=(d-mean)*(d-mean)/s.size();
         }
         
         return sum;
     }
     
    private double calcSizeVariance(GP[] pop){
         double mLength = 0;
         double mFitness = 0;
         for(int i = 0; i < pop.length;i++){
             mLength +=pop[i].getNrOfNodes();
         }
         mLength = mLength/pop.length;
         double var=0;
         for(int i = 0; i < pop.length;i++){
             var +=(pop[i].getNrOfNodes()-mLength)*(pop[i].getNrOfNodes()-mLength);
         }
         
         return var/pop.length;
     }
     
     
     private double calcCoVariance(GP[] pop){
         double mLength = 0;
         double mFitness = 0;
         double punishment = pop[0].getOptions().getPUNISHMENT_FOR_LENGTH();
         for(int i = 0; i < pop.length;i++){
             mLength +=pop[i].getNrOfNodes();
             mFitness+=pop[i].getFitness() - pop[i].getNrOfNodes()*punishment;
         }
         mLength = mLength/pop.length;
         mFitness = mFitness/pop.length;
         double coVar=0;
         for(int i = 0; i < pop.length;i++){
             coVar +=(pop[i].getNrOfNodes()-mLength)*(pop[i].getFitness()- pop[i].getNrOfNodes()*punishment-mFitness);
         }
         
         return coVar/pop.length;
     }
}
